#include "../../cpp/cuda_header.h"
#include "compressOutput_gpu.h"
#include "util.h"

static double total_sort_time = 0.0;
static double total_pos_comp_time = 0.0;
static double total_queryId_comp_time = 0.0;
static double total_misPos_comp_time = 0.0;
static double total_var_comp_time = 0.0;
static double total_misNum_comp_time = 0.0;

static uint32 total_pos_size = 0;
static uint32 total_queryId_size = 0;
static uint32 total_h_pos_size = 0;
static uint32 total_h_queryId_size = 0;
static uint32 total_misPos_size = 0;
static uint32 total_h_misPos_size = 0;
static uint32 h_varPos_size = 0;

void gpu_RunTimeInfoInit()
{
	total_sort_time = 0.0;
	total_pos_size = 0;
	total_queryId_size = 0;
	total_h_pos_size = 0;
	total_h_queryId_size = 0;
	total_misPos_size = 0;
	total_h_misPos_size = 0;
	total_pos_comp_time = 0.0;
	total_queryId_comp_time = 0.0;
	total_misPos_comp_time = 0.0;
	h_varPos_size = 0.0;
}

void gpu_printRunTimeInfo(uint32 blockSize)
{
	printf("gpu time for sort: %.2f\n", total_sort_time);
	printf("gpu pos compress time: %.3f\n", total_pos_comp_time);
	printf("gpu pos compress speed: %.2f\n", (double)total_h_pos_size /(double)total_pos_comp_time);
	printf("gpu pos compress ratio: %.2f\n", (double)total_h_pos_size / (double)total_pos_size );
	printf("gpu queryId compress time: %.3f\n", total_queryId_comp_time);
	printf("gpu queryId compress speed: %.2f\n", (double)total_h_queryId_size/(double)total_queryId_comp_time);
	printf("gpu queryId compress ratio: %.2f\n", (double)total_h_queryId_size / (double)total_queryId_size );
	printf("gpu misPos compress time: %.3f\n", total_misPos_comp_time);
	printf("gpu misPos compress speed: %.2f\n", (double)total_h_misPos_size/(double)total_misPos_comp_time);
	printf("gpu misPos compress ratio: %.2f\n", (double)total_h_misPos_size / (double)total_misPos_size );
	printf("gpu misNum compress time: %.3f\n",  total_misNum_comp_time);
	printf("gpu misNum compress speed: %.2f\n",  blockSize / total_misNum_comp_time);
	printf("gpu var compress time: %.3f\n", total_var_comp_time);
	printf("gpu var compress speed: %.2f\n", h_varPos_size / total_var_comp_time);

	uint32 total_size = total_pos_size + total_queryId_size + total_misPos_size + (h_varPos_size) + (blockSize);
	double total_time = total_pos_comp_time + total_queryId_comp_time + total_misPos_comp_time + total_misNum_comp_time
				+ total_var_comp_time;
	printf("gpu compress speed: %u\n", ceil((double)total_size / (double)total_time));
	printf("total time: %.2f\n", (double)total_time );
}

static void gpu_malloc(uint32** dest, uint32 size)
{
	cudaMalloc((void**)dest, size);
	cudaMemset((*dest), 0, size);
}
static void gpu_malloc(uint8** dest, uint32 size)
{
	cudaMalloc((void**)dest, size);
	cudaMemset((*dest), 0, size);
}

static void free_gpu(uint32** data)
{
	cudaFree(*data);
	(*data) = NULL;
}
static void free_gpu(uint8** data)
{
	cudaFree(*data);
	(*data) = NULL;
}


struct resultCmp {
        __host__ __device__
                bool operator()(const h_result& o1, const h_result& o2) {
                        return o1.pos < o2.pos;
                }
};

struct uint2Cmp {

        __host__ __device__
                bool operator()(const uint2& o1, const uint2& o2) {
                        return o1.x < o2.x;
                }
};
void gpu_test_compress_blockSize(h_result* cpuSA, uint32 numSA1, FILE* resultFile, uint32 blockSize, uint32 Pos0)
{
	INIT_TIMER;	
	START_TIMER;
	gpu_RunTimeInfoInit();
	fseek(resultFile, Pos0, SEEK_SET);
	uint32 block_compressed_size;
	uint64 total_compressed_size = 0;
	printf("output data size: %u\n\n", numSA1 * sizeof(h_result));
	printf("blockSize:%u\n", blockSize);
	int i;	
	for(i=0; i<(numSA1/blockSize); i++) {
		gpu_compressResult(cpuSA + i*blockSize, blockSize, &block_compressed_size, resultFile);
		total_compressed_size += block_compressed_size;
	}
	if(numSA1 % blockSize > 0){
		gpu_compressResult(cpuSA + i*blockSize, numSA1%blockSize, &block_compressed_size, resultFile);
		total_compressed_size += block_compressed_size;
	}
	uint64 curPos = ftell(resultFile);
	printf("compressed size: %u\n", total_compressed_size);
	printf("total compressed ratio: %.2f\n",  ((double)numSA1 * sizeof(h_result))/(double)total_compressed_size);
	END_TIMER;
	PRINT_TIMER_SEC("total time:");
	gpu_printRunTimeInfo(blockSize);
}

void gpu_getVariation(uint8* misPos, uint8* varBase, uint8* variations)
{
        if(variations[1] < variations[3]) {
                misPos[0] = variations[1];
                misPos[1] = variations[3] - variations[1];
                varBase[0] = variations[2];
                varBase[1] = variations[4];
        } else {
                misPos[0] = variations[3];
                misPos[1] = variations[1] - variations[3];
                varBase[0] = variations[4];
                varBase[1] = variations[2];
        }
}

void setTail(uint32* size0, uint32 size)
{
	(*size0) = ceil((double)size/ 16.0) * 16;
}

void mcsort(unsigned int* d_key, h_result* d_dataout, h_result* d_datain,
		const unsigned int numElement) {

	//make the identity
	unsigned int* d_id = NULL;
	gpu_malloc(&d_id, sizeof(unsigned int)*numElement);
	thrust::device_ptr<unsigned int> dptr_id(d_id);	
	thrust::sequence(dptr_id, dptr_id + numElement);	
	unsigned int timer = 0;

	//sorting
	//timer = 0;
	//startTimer(&timer);
	thrust::device_ptr<unsigned int> dptr_key(d_key);
	thrust::sort_by_key(dptr_key, dptr_key + numElement, dptr_id);
	cutilSafeCall(cudaThreadSynchronize());
	//endTimer(&timer, "sort_by_key");

	//gather
	//timer = 0;
	//startTimer(&timer);
	thrust::device_ptr<h_result> dptr_datain(d_datain);
	thrust::device_ptr<h_result> dptr_dataout(d_dataout);
	thrust::gather(dptr_id, dptr_id + numElement, dptr_datain, dptr_dataout);
	cutilSafeCall(cudaThreadSynchronize());
	//endTimer(&timer, "gather");

	//memory cleanup
	free_gpu(&d_id);
}


void gpu_compressResult(h_result* resultBuffer, uint32 blockSize, uint32* compressed_size, FILE* fout)
{
	uint32 i;
	uint32 M_id = 32, M_pos = 1024*1024, M_misPos = 8;
	h_result* d_in, *d_out;
	
	INIT_TIMER;
	
	uint32* h_queryId = (uint32*)malloc(blockSize * sizeof(int));
	uint8* c_h_queryId = (uint8*)malloc(blockSize * sizeof(int));
	uint32* h_pos = (uint32*)malloc(blockSize * sizeof(int));
	uint8* c_h_pos = (uint8*)malloc(blockSize * sizeof(int));
	uint8* h_misNum = (uint8*)malloc(blockSize);
	uint8* c_h_misNum = (uint8*)malloc(ceil((double)blockSize/4.0));
	uint8* h_misPos = (uint8*)malloc(blockSize*2);
	uint8* c_h_misPos = (uint8*)malloc(blockSize * 2);
	uint8* h_varBase = (uint8*)malloc(blockSize*2);
	uint8* c_h_varBase = (uint8*)malloc(blockSize*2);

	uint32 varPosOffset = 0, misPosOffset = 0,c_varPosOffset;
	uint32 c_h_posBitSize, c_h_idBitSize, c_h_misPosBitSize;
	uint32 c_h_posSize, c_h_idSize, c_h_misPosSize, c_h_misNumSize;

/*	START_TIMER;
	uint32 *d_key;
	for(i=0; i<blockSize; i++) {
		h_pos[i] = resultBuffer[i].pos;
	}

	gpu_malloc(&d_key, (uint32)(sizeof(int) * blockSize));
	TOGPU(d_key, h_pos, sizeof(int) * blockSize);		
	cudaMalloc(&d_in, sizeof(h_result) * blockSize);
	cudaMemcpy(d_in, resultBuffer, sizeof(h_result) * blockSize, cudaMemcpyHostToDevice);
	cudaMalloc(&d_out, sizeof(h_result) * blockSize);

	mcsort(d_key, d_out, d_in, blockSize);
	cudaMemcpy(resultBuffer, d_out, sizeof(h_result) * blockSize, cudaMemcpyDeviceToHost);
	cutilSafeCall(cudaFree(d_in));
	cutilSafeCall(cudaFree(d_out));
	free_gpu(&d_key);
	END_TIMER;
	total_sort_time += GET_TIMER_SEC;
*/
	for(i=0; i<blockSize; i++){
		h_queryId[i] = resultBuffer[i].queryId;
		h_pos[i] = resultBuffer[i].pos;
		h_misNum[i] = resultBuffer[i].variation[0];
		
		if(resultBuffer[i].variation[0] == 1){
			h_misPos[misPosOffset++] = resultBuffer[i].variation[1];
			h_varBase[varPosOffset++] = resultBuffer[i].variation[2];
		}
		else if(resultBuffer[i].variation[0] == 2){
			gpu_getVariation(h_misPos + misPosOffset, h_varBase + varPosOffset, resultBuffer[i].variation);
			misPosOffset += 2;
			varPosOffset += 2;
		}
	}
	
	uint32* d_pos, *d_pos_idx,*d_misPos_idx, *d_queryId, *d_queryId_idx; 
	uint8* d_misPos, *d_varBase, *d_misNum, *c_d_pos, *c_d_queryId, *c_d_misPos, *c_d_varBase, *c_d_misNum;
	uint32 blockSize0, misPosOffset0, varPosOffset0;
	
	setTail(&blockSize0, blockSize);
	setTail(&misPosOffset0, misPosOffset);
	setTail(&varPosOffset0, varPosOffset);
	
	gpu_malloc(&d_pos, blockSize0 * sizeof(int));
	gpu_malloc(&d_queryId, blockSize0 * sizeof(int));
	gpu_malloc(&d_misPos, misPosOffset0);
	gpu_malloc(&d_varBase, varPosOffset0);
	gpu_malloc(&d_misNum, blockSize0);
	
	gpu_malloc(&d_pos_idx, (blockSize0+1) * sizeof(int));
	gpu_malloc(&c_d_pos, blockSize0 * sizeof(int));
	gpu_malloc(&d_queryId_idx, (blockSize0+1) * sizeof(int));
	gpu_malloc(&c_d_queryId, blockSize0 * sizeof(int));
	gpu_malloc(&c_d_misPos, misPosOffset0 * sizeof(int));
	gpu_malloc(&d_misPos_idx, (blockSize0+1) * sizeof(int));
	gpu_malloc(&c_d_varBase, varPosOffset0 / 4);
	gpu_malloc(&c_d_misNum, blockSize0 / 4);

	TOGPU(d_pos, h_pos, blockSize * sizeof(int));
	TOGPU(d_queryId, h_queryId, blockSize * sizeof(int));
	TOGPU(d_misNum, h_misNum, blockSize);
	TOGPU(d_misPos,h_misPos, misPosOffset);
	TOGPU(d_varBase,h_varBase,varPosOffset);
	



//	mcsort(d_pos, st_data* d_dataout, st_data* d_datain, const unsigned int numElement);
/*	START_TIMER;
	thrust::device_ptr<uint32> pos_ptr(d_pos);
	thrust::sort(pos_ptr, pos_ptr + blockSize - 1);
	END_TIMER;
	total_sort_time += GET_TIMER_SEC;
*/	//compress pos
	START_TIMER;
	gpu_delta_encoding(d_pos, blockSize);
	cutilSafeCall(cudaMemset(d_pos + blockSize, 0, (blockSize0 - blockSize) * sizeof(int)));

	gpu_golomb_coding(d_pos, blockSize0, d_pos_idx, c_d_pos, &c_h_posBitSize, &M_pos);

	END_TIMER;
	total_pos_comp_time += GET_TIMER_SEC;
	
	//compress queryId
	//M = ?
	START_TIMER;
	uint32 c_queryIdSize = 0;
	
	gpu_golomb_coding(d_queryId, blockSize0, d_queryId_idx, c_d_queryId, &c_h_idBitSize, &M_id);

	END_TIMER;
	total_queryId_comp_time += GET_TIMER_SEC;

	START_TIMER;
	gpu_binary_encoding(d_misNum, blockSize0, c_d_misNum);
	c_h_misNumSize = blockSize / 4;
//	cpu_binaryEncoding_2bit(h_misNum, c_h_misNum, blockSize, &c_h_misNumSize);
	END_TIMER;
	total_misNum_comp_time += GET_TIMER_SEC;

	//compress misPos
	START_TIMER;
	uint32 c_misPosOffset = 0;

	gpu_golomb_coding(d_misPos, blockSize0, d_misPos_idx, c_d_misPos, &c_h_misPosBitSize, &M_misPos);
	END_TIMER;
	total_misPos_comp_time += GET_TIMER_SEC;

	//binary compress dna variation
	START_TIMER;
	gpu_binary_encoding(d_varBase, varPosOffset0, c_d_varBase);
	c_varPosOffset = ceil((double) varPosOffset / 4.0);
	h_varPos_size += varPosOffset;
	END_TIMER;
	total_var_comp_time += GET_TIMER_SEC;


	cutilSafeCall(cudaMemcpy(&c_h_posBitSize, d_pos_idx+blockSize, sizeof(int), cudaMemcpyDeviceToHost));
	c_h_posSize = ceil((double)c_h_posBitSize/8.0);
	total_pos_size += c_h_posSize;
	total_h_pos_size += blockSize * sizeof(int);	

	cutilSafeCall(cudaMemcpy(&c_h_idBitSize, d_queryId_idx + blockSize, sizeof(int), cudaMemcpyDeviceToHost));
	c_h_idSize = ceil((double)c_h_idBitSize/8.0);
	total_queryId_size += c_h_idSize;
	total_h_queryId_size += blockSize * sizeof(int);

	cutilSafeCall(cudaMemcpy(&c_h_misPosBitSize, d_misPos_idx + blockSize, sizeof(int), cudaMemcpyDeviceToHost));
	c_h_misPosSize = ceil((double)c_h_misPosBitSize/8.0);
	total_misPos_size += c_h_misPosSize;
	total_h_misPos_size += misPosOffset;

	FROMGPU(c_h_pos, c_d_pos, c_h_posSize);
	FROMGPU(c_h_queryId, c_d_queryId, c_h_idSize);
	FROMGPU(c_h_misPos, c_d_misPos, c_h_misPosSize);
	FROMGPU(c_h_varBase, c_d_varBase, ceil((double)varPosOffset /4.0));
	FROMGPU(c_h_misNum, c_d_misNum, ceil((double)blockSize / 4.0));

	
//	START_TIMER
	fwrite(&blockSize, sizeof(int), 1, fout);
	fwrite(&M_id,sizeof(int),1,fout);
	fwrite(&c_h_idBitSize, sizeof(uint64), 1, fout);
	fwrite(&M_pos, sizeof(int), 1, fout);
	fwrite(&c_h_posBitSize, sizeof(uint64), 1, fout);
	fwrite(&M_misPos, sizeof(int), 1, fout);
	fwrite(&misPosOffset, sizeof(int), 1, fout);
	fwrite(&c_h_misPosBitSize, sizeof(uint64), 1, fout);
	fwrite(&varPosOffset, sizeof(int), 1, fout);
	fwrite(&c_varPosOffset, sizeof(int), 1, fout);
	
	fwrite(c_h_queryId, 1, c_h_idSize, fout);
	fwrite(c_h_pos, 1, c_h_posSize, fout);
	fwrite(c_h_misNum, 1, ceil((double)blockSize/4.0), fout);
	fwrite(c_h_misPos,1,c_h_misPosSize, fout);
	fwrite(c_h_varBase,1,c_varPosOffset, fout);

//	END_TIMER
//	PRINT_TIMER_SEC("compress disk access time: ");

	(*compressed_size) = c_h_idSize + c_h_posSize + ceil((double)blockSize/4.0) 
			+ c_h_misPosSize + c_varPosOffset;
	
	free(c_h_queryId);
	free(c_h_pos);
	free(c_h_misNum);
	free(c_h_misPos);
	free(c_h_varBase);

	free(h_queryId);
	free(h_misNum);
	free(h_pos);
	free(h_misPos);
	free(h_varBase);

	free_gpu(&d_pos);
	free_gpu(&c_d_pos);
	free_gpu(&d_queryId);
	free_gpu(&c_d_queryId);
	free_gpu(&d_misNum);
	free_gpu(&c_d_misNum);
	free_gpu(&d_misPos);
	free_gpu(&c_d_misPos);
	free_gpu(&d_varBase);
	free_gpu(&c_d_varBase);

}

/*
uint32 decompressResult(h_result** resultBuffer_ptr, uint32* resultSize, FILE* fin)
{
	uint32 blockSize, M_id, M_pos, M_misPos, c_queryIdSize,
		varPosOffset = 0, c_varPosOffset = 0, c_h_posSize=0, misPosOffset = 0,c_misPosOffset;
	uint64 c_h_posBitSize, c_h_idBitSize, c_h_misPosBitSize;
	uint32 i;
	
	fread(&blockSize, sizeof(int), 1, fin);
	fread(&M_id,sizeof(int),1,fin);
	fread(&c_h_idBitSize, sizeof(uint64), 1, fin);
	fread(&M_pos, sizeof(int), 1, fin);
	fread(&c_h_posBitSize, sizeof(uint64), 1, fin);
	fread(&M_misPos, sizeof(int), 1, fin);
	fread(&misPosOffset, sizeof(int), 1, fin);
	fread(&c_h_misPosBitSize, sizeof(uint64), 1, fin);
	fread(&varPosOffset, sizeof(int), 1, fin);
	fread(&c_varPosOffset, sizeof(int), 1, fin);


	h_result* resultBuffer = (h_result*)malloc(blockSize * sizeof(h_result));
	uint32* h_queryId = (uint32*)malloc(blockSize * sizeof(int));
	uint32* h_pos = (uint32*)malloc(blockSize * sizeof(int));
	uint8* c_h_misNum = (uint8*)malloc(ceil((double)blockSize/4.0));
	uint8* h_misNum = (uint8*)malloc(ceil((double)blockSize/4.0) * 4);
	
	
	c_queryIdSize = ceil((double)c_h_idBitSize/8.0);
	uint8* c_h_queryId = (uint8*)malloc(c_queryIdSize);
	c_h_posSize = ceil((double)c_h_posBitSize/8.0);
	uint8* c_h_pos = (uint8*)malloc(c_h_posSize);
	c_misPosOffset = ceil((double)c_h_misPosBitSize/8.0);
	uint8* c_h_misPos = (uint8*)malloc(c_misPosOffset);
	uint8* h_misPos = (uint8*)malloc(misPosOffset);
	uint8* c_h_varBase = (uint8*)malloc(c_varPosOffset);
	uint8* h_varBase = (uint8*)malloc(c_varPosOffset*4);

	INIT_TIMER
	START_TIMER

	fread(c_h_queryId, 1, c_queryIdSize, fin);
	fread(c_h_pos, 1, c_h_posSize, fin);
	fread(c_h_misNum, 1, ceil((double)blockSize/4.0), fin);
	fread(c_h_misPos,1,c_misPosOffset, fin);
	fread(c_h_varBase,1, c_varPosOffset, fin);
	
	END_TIMER
	PRINT_TIMER_SEC("decompress read from disk time: ");

	//decompress queryId
	golombDecode(c_h_queryId, h_queryId, M_id, c_h_idBitSize);

	//decompress positions
	golombDecode(c_h_pos, h_pos, M_pos, c_h_posBitSize);
	cpu_delta_decompress((int*)h_pos, blockSize, 1);
	
	//decompress misNum
	cpu_binaryDecoding_2bit(c_h_misNum, h_misNum, ceil((double)blockSize/4.0));
	
	//decompress mismatch pos
	golombDecode(c_h_misPos, h_misPos, M_misPos, c_h_misPosBitSize);

	//decompress variations	
	cpu_binaryDecoding_2bit(c_h_varBase, h_varBase, c_varPosOffset);

	varPosOffset = 0;
	misPosOffset = 0;
	for(i=0; i<blockSize; i++) {
		resultBuffer[i].queryId = h_queryId[i];
		resultBuffer[i].pos = h_pos[i];
		resultBuffer[i].variation[0] = h_misNum[i];
		if(h_misNum[i] > 0) {
			resultBuffer[i].variation[1] = h_misPos[misPosOffset++];
			resultBuffer[i].variation[2] = h_varBase[varPosOffset++];
		}
		if(h_misNum[i] > 1){
			resultBuffer[i].variation[3] = h_misPos[misPosOffset] + h_misPos[misPosOffset-1];
			misPosOffset++;
			resultBuffer[i].variation[4] = h_varBase[varPosOffset++];		
		}
	}
	(*resultBuffer_ptr) = resultBuffer;
	(*resultSize) = blockSize;

	free(c_h_queryId);
	free(c_h_pos);
	free(c_h_misNum);
	free(c_h_misPos);
	free(c_h_varBase);

	free(h_queryId);
	free(h_misNum);
	free(h_pos);
	free(h_misPos);
	free(h_varBase);

	return blockSize;
}

void CPUPrintResult(h_result* outSA, uint32 numSA, FILE* outFile)
{
        uint32 i;
        for(i=0; i<numSA; i++) {
                fprintf(outFile, "%u %u %d ", outSA[i].queryId, outSA[i].pos, outSA[i].variation[0]);
                if(outSA[i].variation[0] > 0)
                        fprintf(outFile, "%d %d ", outSA[i].variation[1], outSA[i].variation[2]);
                if(outSA[i].variation[0] > 1)
                        fprintf(outFile, "%d %d ", outSA[i].variation[3], outSA[i].variation[4]);
                fprintf(outFile,"\n");
        }
}

uint8 getDNA(uint8 c) {
	if(c == 0)
		return 'A';
	else if(c==1)
		return 'C';
	else if(c==2)
		return 'G';
	else 
		return 'T';
}

void print_full_size_result_cpu(h_result* outSA, uint32 numSA, FILE* outFile, 
								char* titleBuffer,const int max_title_size, char* ref, 
								const int queryLen)
{
	PRINT_FUNC_NAME;
	INIT_TIMER;
	START_TIMER;

        uint32 i,j,k,tempPos;
        for(i=0; i<numSA; i++) {
				fprintf(outFile, "%s ", &(titleBuffer[outSA[i].queryId * max_title_size]));
				tempPos = outSA[i].pos;
				for(j=0; j< queryLen; j++) {
					if(ref[tempPos] == '\n')
						tempPos++;
					fprintf(outFile,"%c",ref[tempPos]);
					tempPos++;
				}
				fprintf(outFile," ");
                fprintf(outFile, "%d ",outSA[i].variation[0]);

                if(outSA[i].variation[0] > 0)
                        fprintf(outFile, "%d%c", outSA[i].variation[1], getDNA(outSA[i].variation[2]));
                if(outSA[i].variation[0] > 1)
                        fprintf(outFile, "%d%c", outSA[i].variation[3], getDNA(outSA[i].variation[4]));
                fprintf(outFile,"\n");
        }
	END_TIMER;
	PRINT_TIMER_SEC("write to disk time: ");
}


int main()
{
	char* inFileName = "output";
	char* outFileName = "compressedOutput";
	char* outFileName2 = "decompressedOutput";
	const int dataSize = 63645427;
	const int blockSize = 10000000;
	uint32 total_compressed_size = 0, block_compressed_size = 0;
	FILE* fin = fopen(inFileName, "r");
	FILE* fout = fopen(outFileName, "wb");
	h_result* outputBuffer = (h_result*)malloc(dataSize * sizeof(h_result));
	for(int i=0; i<dataSize; i++) {
		fscanf(fin,"%u %u %d" , &(outputBuffer[i].queryId), &(outputBuffer[i].pos), &(outputBuffer[i].variation[0]));
		if(outputBuffer[i].variation[0] == 1)
			fscanf(fin, "%d %d",&(outputBuffer[i].variation[1]),&(outputBuffer[i].variation[2]));
		else if(outputBuffer[i].variation[0] == 2)
			fscanf(fin, "%d %d %d %d",&(outputBuffer[i].variation[1]),&(outputBuffer[i].variation[2]),
			&(outputBuffer[i].variation[3]),&(outputBuffer[i].variation[4]));
		fscanf(fin,"\n");
	}
	INIT_TIMER;
	START_TIMER;
	for(int i=0; i<dataSize/blockSize ; i++) {
		printf("block %d\n",i);
		compressResult(outputBuffer + i*blockSize, blockSize, &block_compressed_size, fout);
		printf("before compress: %u, after compress: %u\n\n", blockSize*sizeof(h_result), 
				block_compressed_size);
		total_compressed_size += block_compressed_size;
	}
	printf("block %d\n",dataSize/blockSize);
	compressResult(outputBuffer + dataSize/blockSize*blockSize, dataSize%blockSize, &block_compressed_size, fout);
	printf("before compress: %u, after compress: %u\n\n", (dataSize %blockSize)*sizeof(h_result), 
			block_compressed_size);
	total_compressed_size += block_compressed_size;
	printf("total compressed size: %u\n", total_compressed_size);
	printf("compression done\n\n\n");
	END_TIMER;
	PRINT_TIMER_SEC("compression time: ");

	fclose(fin);
	fclose(fout);
	free(outputBuffer);

	FILE* fin2 = fopen(outFileName, "rb");
	FILE* fout2 = fopen(outFileName2, "w");
	
	START_TIMER;
	uint32 resultSize = 0, totalSize = 0;
	while(totalSize < dataSize) {
		totalSize += decompressResult(&outputBuffer, &resultSize, fin2);
		CPUPrintResult(outputBuffer, resultSize, fout2);
		free(outputBuffer);
	}
	printf("decompression done\n\n\n");
	END_TIMER;
	PRINT_TIMER_SEC("decompression time: ");
	fclose(fin2);
	fclose(fout2);
	return 0;
}
*/
